#pragma once

#include <brpc/server.h>
#include <butil/logging.h>
#include <cctype>
#include <regex>

#include "etcd.hpp"
#include "logger.hpp"
#include "base.pb.h"
#include "user.pb.h"
#include "file.pb.h"
#include "utils.hpp"
#include "es_data.hpp"
#include "channel.hpp"
#include "mysql_user.hpp"
#include "redis_data.hpp"

 
namespace xu
{
    //检查昵称是否合法
    bool CheckNickname(const std::string & nickname)
    {
        return nickname.size() >= 1 && nickname.size() <= 21;
    }

    //检查密码是否合法
    bool CheckPassword(const std::string& password) {
        // 检查密码长度是否在6到15个字符之间
        if (password.length() < 6 || password.length() > 15) {
            return false;
        }

        // 遍历密码中的每个字符
        for (char c : password) {
            // 检查字符是否既不是字母也不是数字
            if (!std::isalnum(c)) {
                return false;
            }
        }

        // 如果所有检查都通过，则密码合法
        return true;
    }


    //验证手机号码是否正确
    bool IsValidPhoneNumber(const std::string& phoneNumber) 
    {
        // 定义手机号码的正则表达式模式
        const std::regex pattern(R"(^1[3-9]\d{9}$)");
        
        // 执行正则表达式匹配
        return std::regex_match(phoneNumber, pattern);
    }

    class UserServicelmpl :public xu::UserService
    {
    public:
        UserServicelmpl(
        const std::string &file_service_name,
        ServiceManage::ptr service_manage,
        std::shared_ptr<elasticlient::Client> es_client,
        std::shared_ptr<odb::mysql::database> mysql_client,
        std::shared_ptr<sw::redis::Redis> redis_client)
        :_file_service_name(file_service_name),
        _service_manage(service_manage),
        _es_user(std::make_shared<ESUser>(es_client)),
        _mysql_user(std::make_shared<ManageUser>(mysql_client)),
        _session(std::make_shared<Session>(redis_client)),    
        _status(std::make_shared<Status>(redis_client)),
        _codes(std::make_shared<Codes>(redis_client))
        {}
        ~UserServicelmpl(){}

        //昵称注册
        virtual void UserRegister(::google::protobuf::RpcController* controller,
                       const ::xu::UserRegisterReq* request,
                       ::xu::UserRegisterRsp* response,
                       ::google::protobuf::Closure* done) override
        {   
            brpc::ClosureGuard clo(done);
            response->set_request_id(request->request_id()); 
            auto err_rsp = [this,response](const std::string & err_msg)
            {
                response->set_success(false);
                response->set_errmsg(err_msg);
            };
            // 1. 从请求中取出昵称和密码
            std::string nickname = request->nickname();
            std::string password = request->password();
            // 2. 检查昵称是否合法（只能包含字母，数字，连字符-，下划线_，长度限制 3~15 之间）
            if(CheckNickname(nickname) == false)
            {
                LOG_ERROR("昵称格式错误：{}",nickname);
                err_rsp("昵称格式错误");
                return;
            }
            // 3. 检查密码是否合法（只能包含字母，数字，长度限制 6~15 之间）
            if(CheckPassword(password) == false)
            {
                LOG_ERROR("密码格式错误：{}",password);
                err_rsp("密码格式错误");
                return;
            }
            // 4. 根据昵称在数据库进行判断是否昵称已存在
            auto ret = _mysql_user->SelectNickName(nickname);
            if(ret)
            {
                LOG_ERROR("数据库中存在：{}",nickname);
                err_rsp("用户昵称已被注册");
                return;
            }

            // 5. 向数据库新增数据
            User user(uuid(),nickname,password);
            if(_mysql_user->Insert(user) == false)
            {
                LOG_ERROR("插入数据库失败:{}",nickname);
                err_rsp("插入数据库失败");
                return;
            }
            // 6. 向 ES 服务器中新增用户信息
            if(_es_user->Insert(user) == false)
            {
                LOG_ERROR("插入Es搜索引擎失败失败:{}",nickname);
                //将插入数据的数据删除
                ret = _mysql_user->SelectNickName(nickname);
                if(ret) _mysql_user->Delete(*ret);
                err_rsp("插入Es搜索引擎失败失败");
                return;
            }

            // 7. 组织响应，进行成功与否的响应即可
            response->set_success(true);
        }     
        //昵称登录          
        virtual void UserLogin(::google::protobuf::RpcController* controller,
                            const ::xu::UserLoginReq* request,
                            ::xu::UserLoginRsp* response,
                            ::google::protobuf::Closure* done) override
        {
            brpc::ClosureGuard clo(done);
            response->set_request_id(request->request_id()); 
            auto err_rsp = [this,response](const std::string & err_msg)
            {
                response->set_success(false);
                response->set_errmsg(err_msg);
            };

            // 1. 从请求中取出昵称和密码
            std::string nickname = request->nickname();
            std::string password = request->password();
            // 2. 通过昵称获取用户信息，进行密码是否一致的判断
            auto ret = _mysql_user->SelectNickName(nickname);
            if(!ret)
            {
                LOG_ERROR("数据库中不存在：{}",nickname);
                err_rsp("用户昵称未注册");
                return;
            }
            if(ret->password() != password)
            {
                LOG_ERROR("密码错误 ：{} - {}",ret->password(),password);
                err_rsp("密码错误");
                return; 
            }
            // 3. 根据 redis 中的登录标记信息是否存在判断用户是否已经登录。
            if(_status->Exist(ret->user_id()) == true)
            {
                LOG_ERROR("用户重复登录：{}",nickname);
                err_rsp("用户重复登录");
                return;
            }
          
            // 4. 构造会话 ID，生成会话键值对，向 redis 中添加会话信息以及登录标记信息
            std::string sid = uuid();
            _session->Append(sid,ret->user_id());
            _status->Append(ret->user_id());
            // 5. 组织响应，返回生成的会话 ID
            response->set_success(true);
            response->set_login_session_id(sid); 
        }

        //获取手机验证码
        virtual void GetPhoneVerifyCode(::google::protobuf::RpcController* controller,
                            const ::xu::PhoneVerifyCodeReq* request,
                            ::xu::PhoneVerifyCodeRsp* response,
                            ::google::protobuf::Closure* done) override
        {
            brpc::ClosureGuard clo(done);
            response->set_request_id(request->request_id()); 
            auto err_rsp = [this,response](const std::string & err_msg)
            {
                response->set_success(false);
                response->set_errmsg(err_msg);
            };

            // 1. 从请求中取出手机号码
            std::string phone_number = request->phone_number();
            // 2. 验证手机号码格式是否正确（必须以 1 开始，第二位 3~9 之间，后边 9 个数字字符）
            if(IsValidPhoneNumber(phone_number) == false)
            {
                LOG_ERROR("手机号码格式错误：{}",phone_number);
                err_rsp("手机号码格式错误");
                return;
            }
            // 3. 生成 4 位随机验证码
            std::string vcode = "1111";
            // 4. 基于短信平台 SDK 发送验证码

            // 5. 构造验证码 ID，添加到 redis 验证码映射键值索引中
            std::string cid = uuid();
            _codes->Append(cid,vcode);
            // 6. 组织响应，返回生成的验证码 ID
            response->set_verify_code_id(cid);
            response->set_success(true);
        }

        //手机号码注册
        virtual void PhoneRegister(::google::protobuf::RpcController* controller,
                            const ::xu::PhoneRegisterReq* request,
                            ::xu::PhoneRegisterRsp* response,
                            ::google::protobuf::Closure* done) override
        {
            brpc::ClosureGuard clo(done);
            response->set_request_id(request->request_id()); 
            auto err_rsp = [this,response](const std::string & err_msg)
            {
                response->set_success(false);
                response->set_errmsg(err_msg);
            };

            // 1. 从请求中取出手机号码和验证码
            std::string phone_number = request->phone_number();
            std::string verify_code = request->verify_code();
            std::string verify_code_id = request->verify_code_id();
            // 2. 检查注册手机号码是否合法
            if(IsValidPhoneNumber(phone_number) == false)
            {
                LOG_ERROR("手机号码格式错误：{}",phone_number);
                err_rsp("手机号码格式错误");
                return;
            }
            // 3. 从 redis 数据库中进行验证码 ID-验证码一致性匹配
            auto code = _codes->GetCode(verify_code_id);
            if(!code)
            {
                LOG_ERROR("验证码不存在：{}",verify_code_id);
                err_rsp("验证码不存在");
                return;
            }
            if(*code != verify_code)
            {
                LOG_ERROR("验证码错误：{}",verify_code_id);
                err_rsp("验证码错误");
                return;
            } 

            //验证通过删除验证码
            _codes->Remove(verify_code_id);

            // 4. 通过数据库查询判断手机号是否已经注册过
            auto ret = _mysql_user->SelectPhoneNumber(phone_number);
            if(ret)
            {
                LOG_ERROR("数据库中存在：{}",phone_number);
                err_rsp("用户手机号已被注册");
                return;
            }
            // 5. 向数据库新增用户信息
            std::string uid = uuid();
            User user(uid,phone_number);
            _mysql_user->Insert(user);

            // 6. 向 ES 服务器中新增用户信息
            if(_es_user->Insert(user) == false)
            {
                LOG_ERROR("插入Es搜索引擎失败失败:{}",nickname);
                //将插入数据的数据删除
                ret = _mysql_user->SelectPhoneNumber(phone_number);
                if(ret) _mysql_user->Delete(*ret);
                err_rsp("插入Es搜索引擎失败失败");
                return;
            }

            // 7. 组织响应，返回注册成功与否
            response->set_success(true);
        }

        //手机号码登录
        virtual void PhoneLogin(::google::protobuf::RpcController* controller,
                            const ::xu::PhoneLoginReq* request,
                            ::xu::PhoneLoginRsp* response,
                            ::google::protobuf::Closure* done) override
        {
            brpc::ClosureGuard clo(done);
            response->set_request_id(request->request_id()); 
            auto err_rsp = [this,response](const std::string & err_msg)
            {
                response->set_success(false);
                response->set_errmsg(err_msg);
            };

            // 1. 从请求中取出手机号码和验证码 ID，以及验证码。
            std::string phone_number = request->phone_number();
            std::string verify_code = request->verify_code();
            std::string verify_code_id = request->verify_code_id();
            // 2. 检查注册手机号码是否合法
            if(IsValidPhoneNumber(phone_number) == false)
            {
                LOG_ERROR("手机号码格式错误：{}",phone_number);
                err_rsp("手机号码格式错误");
                return;
            }
            // 3. 从 redis 数据库中进行验证码 ID-验证码一致性匹配
            auto code = _codes->GetCode(verify_code_id);
            if(!code)
            {
                LOG_ERROR("验证码不存在：{}",verify_code_id);
                err_rsp("验证码不存在");
                return;
            }
            if(*code != verify_code)
            {
                LOG_ERROR("验证码错误：{}",verify_code_id);
                err_rsp("验证码错误");
                return;
            } 

            //验证通过删除验证码
            _codes->Remove(verify_code_id);

            // 4. 根据手机号从数据数据进行用户信息查询，判断用用户是否存在
            auto ret = _mysql_user->SelectPhoneNumber(phone_number);
            if(!ret)
            {
                LOG_ERROR("数据库中不存在：{}",phone_number);
                err_rsp("用户手机号未注册");
                return;
            }

            // 5. 根据 redis 中的登录标记信息是否存在判断用户是否已经登录。
            if(_status->Exist(ret->user_id()) == true)
            {
                LOG_ERROR("用户重复登录：{}",phone_number);
                err_rsp("用户重复登录");
                return;
            }
          
            // 6. 构造会话 ID，生成会话键值对，向 redis 中添加会话信息以及登录标记信息
            std::string sid = uuid();
            _session->Append(sid,ret->user_id());
            _status->Append(ret->user_id());
            // 7. 组织响应，返回生成的会话 ID
            response->set_success(true);
            response->set_login_session_id(sid); 
        }
        
        //获取用户信息
        virtual void GetUserInfo(::google::protobuf::RpcController* controller,
                            const ::xu::GetUserInfoReq* request,
                            ::xu::GetUserInfoRsp* response,
                            ::google::protobuf::Closure* done) override 
        {
            brpc::ClosureGuard clo(done);
            response->set_request_id(request->request_id()); 
            auto err_rsp = [this,response](const std::string & err_msg)
            {
                response->set_success(false);
                response->set_errmsg(err_msg);
            };

            // 1. 从请求中取出用户 ID
            std::string uid = request->user_id();
            // 2. 通过用户 ID，从数据库中查询用户信息
            auto ret = _mysql_user->SelectUserId(uid);
            if(!ret)
            {
                LOG_ERROR("数据库中不存在：{}", uid );
                err_rsp("用户不存在");
                return;
            }
            // 3. 根据用户信息中的头像 ID，从文件服务器获取头像文件数据，组织完整用户信息
            auto avatar_id = ret->avatar_id();
            if(avatar_id.empty() == false)
            {
                auto channel = _service_manage->Choose(_file_service_name);
                xu::FileService_Stub stub(channel.get());
                brpc::Controller cntl;
                xu::GetSingleFileReq req;
                xu::GetSingleFileRsp rsp;
                req.set_request_id(uuid());
                req.set_file_id(avatar_id);
                stub.GetSingleFile(&cntl,&req,&rsp,nullptr);
                if(cntl.Failed())
                {
                    LOG_ERROR("用户头像不存在：{}", uid );
                    err_rsp("用户头像不存在");
                    return;
                }
                response->mutable_user_info()->set_avatar(rsp.file_data().file_content());
            }
            

            // 4. 组织响应，返回用户信息
            response->set_success(true);
            response->mutable_user_info()->set_user_id(uid);
            response->mutable_user_info()->set_nickname(ret->nickname());
            response->mutable_user_info()->set_description(ret->description());
            response->mutable_user_info()->set_phone(ret->phone_number());

        }                    
        virtual void GetMultiUserInfo(::google::protobuf::RpcController* controller,
                            const ::xu::GetMultiUserInfoReq* request,
                            ::xu::GetMultiUserInfoRsp* response,
                            ::google::protobuf::Closure* done) override
        {
            brpc::ClosureGuard clo(done);
            response->set_request_id(request->request_id()); 
            auto err_rsp = [this,response](const std::string & err_msg)
            {
                response->set_success(false);
                response->set_errmsg(err_msg);
            };

            //1.获取批量user_id
            std::vector<std::string> user_ids;
            for(int i = 0; i < request->users_id_size(); ++i)
            {
                user_ids.push_back(request->users_id(i));
            }
            
            //2.从数据库中获取用户信息
            auto ret = _mysql_user->SelectListUserId(user_ids);
            if(ret.empty())
            {
                LOG_ERROR("数据库中不存在这批用户");
                err_rsp("存在用户不存在");
                return;
            }
            //3.根据用户信息中的头像 ID，从文件服务器获取头像文件数据，组织完整用户信息
            auto channel = _service_manage->Choose(_file_service_name);
            xu::FileService_Stub stub(channel.get());
            xu::GetMultiFileReq req;
            xu::GetMultiFileRsp* rsp = new xu::GetMultiFileRsp();
            brpc::Controller *cntl = new brpc::Controller();
            req.set_request_id(uuid());
            for(int i = 0; i < ret.size(); ++i)
            {
                if(!ret[i].avatar_id().empty())
                    req.add_file_id_list(ret[i].avatar_id());
            }
            stub.GetMultiFile(cntl,&req,rsp,nullptr);
            if(cntl->Failed())
            {
                LOG_ERROR("用户头像不存在" );
                err_rsp("用户头像不存在");
                return;
            }
            //4.组织响应
            auto map = rsp->file_data();
            // if(map.size() != ret.size())
            // {
            //     LOG_ERROR("数据出错" );
            //     err_rsp("数据出错");
            //     return;
            // }
            for(int i = 0; i < ret.size(); ++i)
            {
                UserInfo user_info;
                user_info.set_user_id(ret[i].user_id());
                user_info.set_nickname(ret[i].nickname());
                user_info.set_description(ret[i].description());
                user_info.set_phone(ret[i].phone_number());
                    // for(int i = 0; i < file_ids.size(); ++i)
    // {
    //     ASSERT_TRUE(map.find(file_ids[i]) !=  map.end());
    //     auto file_data = map[file_ids[i]];
    //     ASSERT_EQ(xu::WriteFile(file_data.file_id(),file_data.file_content()),true);
    // }
                if(map.find(ret[i].avatar_id()) !=  map.end())
                {
                    auto file_data = map[ret[i].avatar_id()];
                    user_info.set_avatar(file_data.file_content());
                }
                response->mutable_users_info()->insert({ret[i].user_id(),user_info});
            }
            response->set_success(true);
        }
        virtual void SetUserAvatar(::google::protobuf::RpcController* controller,
                            const ::xu::SetUserAvatarReq* request,
                            ::xu::SetUserAvatarRsp* response,
                            ::google::protobuf::Closure* done)override
        {
            brpc::ClosureGuard clo(done);
            response->set_request_id(request->request_id()); 
            auto err_rsp = [this,response](const std::string & err_msg)
            {
                response->set_success(false);
                response->set_errmsg(err_msg);
            };

            // 1. 从请求中取出用户 ID 与头像数据
            std::string user_id = request->user_id();
            std::string avatar = request->avatar();
            // 2. 从数据库通过用户 ID 进行用户信息查询，判断用户是否存在
            auto ret = _mysql_user->SelectUserId(user_id);
            if(!ret)
            {
                LOG_ERROR("数据库中不存在：{}", user_id );
                err_rsp("用户不存在");
                return;
            }
            // 3. 上传头像文件到文件子服务
            auto channel = _service_manage->Choose(_file_service_name);
            xu::FileService_Stub stub(channel.get());
            xu::PutSingleFileReq req;
            xu::PutSingleFileRsp* rsp = new xu::PutSingleFileRsp();
            brpc::Controller *cntl = new brpc::Controller();

            req.set_request_id(uuid());
            req.mutable_file_data()->set_file_content(avatar);
            req.mutable_file_data()->set_file_name("avatar");
            req.mutable_file_data()->set_file_size(avatar.size());

            stub.PutSingleFile(cntl,&req,rsp,nullptr);
            if(cntl->Failed() || rsp->success() == false)
            {
                LOG_ERROR("用户头像上传失败" );
                err_rsp("用户头像上传失败");
                return;
            }
            // 4. 将返回的头像文件 ID 更新到数据库中
            ret->avatar_id(rsp->file_info().file_id());
            if(_mysql_user->Update(*ret) == false)
            {
                LOG_ERROR("用户头像id插入数据库失败" );
                err_rsp("用户头像id插入数据库失败");
                return;
            }
            // 5. 更新 ES 服务器中用户信息
            if(_es_user->Insert(*ret)== false)
            {
                LOG_ERROR("用户头像id插入搜索引擎失败" );
                err_rsp("用户头像id插入搜索引擎失败");
                return;
            }
            // 6. 组织响应，返回更新成功与否
            response->set_success(true);

        }
        //设置昵称
        virtual void SetUserNickname(::google::protobuf::RpcController* controller,
                            const ::xu::SetUserNicknameReq* request,
                            ::xu::SetUserNicknameRsp* response,
                            ::google::protobuf::Closure* done)override
        {
            brpc::ClosureGuard clo(done);
            response->set_request_id(request->request_id()); 
            auto err_rsp = [this,response](const std::string & err_msg)
            {
                response->set_success(false);
                response->set_errmsg(err_msg);
            };
            // 1. 从请求中取出用户 ID 与新的昵称
            std::string user_id = request->user_id();
            std::string nickname = request->nickname();
            // 2. 判断昵称格式是否正确
            if(CheckNickname(nickname) == false)
            {
                LOG_ERROR("昵称格式错误：{}",nickname);
                err_rsp("昵称格式错误");
                return;
            }
            // 3. 从数据库通过用户 ID 进行用户信息查询，判断用户是否存在
            auto ret = _mysql_user->SelectUserId(user_id);
            if(!ret)
            {
                LOG_ERROR("数据库中不存在：{}", user_id );
                err_rsp("用户不存在");
                return;
            }
            // 4. 将新的昵称更新到数据库中
            ret->nickname(nickname);
           if(_mysql_user->Update(*ret) == false)
            {
                LOG_ERROR("用户昵称插入数据库失败" );
                err_rsp("用户昵称插入数据库失败");
                return;
            }
            // 5. 更新 ES 服务器中用户信息
            if(_es_user->Insert(*ret)== false)
            {
                LOG_ERROR("用户昵称插入搜索引擎失败" );
                err_rsp("用户昵称插入搜索引擎失败");
                return;
            }
            // 6. 组织响应，返回更新成功与否
            response->set_success(true);
        }

        //设置签名
        virtual void SetUserDescription(::google::protobuf::RpcController* controller,
                            const ::xu::SetUserDescriptionReq* request,
                            ::xu::SetUserDescriptionRsp* response,
                            ::google::protobuf::Closure* done)override
        {
            brpc::ClosureGuard clo(done);
            response->set_request_id(request->request_id()); 
            auto err_rsp = [this,response](const std::string & err_msg)
            {
                response->set_success(false);
                response->set_errmsg(err_msg);
            };
            // 1. 从请求中取出用户 ID 与新的签名
            std::string user_id = request->user_id();
            std::string description = request->description();
            // 2. 从数据库通过用户 ID 进行用户信息查询，判断用户是否存在
            auto ret = _mysql_user->SelectUserId(user_id);
            if(!ret)
            {
                LOG_ERROR("数据库中不存在：{}", user_id );
                err_rsp("用户不存在");
                return;
            }
            // 3. 将新的签名更新到数据库中
            ret->description(description);
            if(_mysql_user->Update(*ret) == false)
            {
                LOG_ERROR("用户签名插入数据库失败" );
                err_rsp("用户签名插入数据库失败");
                return;
            }
            // 5. 更新 ES 服务器中用户信息
            if(_es_user->Insert(*ret)== false)
            {
                LOG_ERROR("用户签名插入搜索引擎失败" );
                err_rsp("用户签名插入搜索引擎失败");
                return;
            }
            // 6. 组织响应，返回更新成功与否
            response->set_success(true);
        }
        //设置绑定手机号
        virtual void SetUserPhoneNumber(::google::protobuf::RpcController* controller,
                            const ::xu::SetUserPhoneNumberReq* request,
                            ::xu::SetUserPhoneNumberRsp* response,
                            ::google::protobuf::Closure* done)override
        {   
            brpc::ClosureGuard clo(done);
            response->set_request_id(request->request_id()); 
            auto err_rsp = [this,response](const std::string & err_msg)
            {
                response->set_success(false);
                response->set_errmsg(err_msg);
            };
            // 1. 从请求中取出手机号码和验证码 ID，以及验证码。
            std::string user_id = request->user_id();
            std::string phone_number = request->phone_number();
            std::string verify_code = request->phone_verify_code();
            std::string verify_code_id = request->phone_verify_code_id();
            // 2. 检查注册手机号码是否合法
            if(IsValidPhoneNumber(phone_number) == false)
            {
                LOG_ERROR("手机号码格式错误：{}",phone_number);
                err_rsp("手机号码格式错误");
                return;
            }
            // 3. 从 redis 数据库中进行验证码 ID-验证码一致性匹配
            auto code = _codes->GetCode(verify_code_id);
            if(!code)
            {
                LOG_ERROR("验证码不存在：{}",verify_code_id);
                err_rsp("验证码不存在");
                return;
            }
            if(*code != verify_code)
            {
                LOG_ERROR("验证码错误：{}",verify_code_id);
                err_rsp("验证码错误");
                return;
            }

            //验证通过删除验证码
            _codes->Remove(verify_code_id);

            // 4. 根据手机号从数据数据进行用户信息查询，判断用用户是否存在
            auto ret = _mysql_user->SelectUserId(user_id);
            if(!ret)
            {
                LOG_ERROR("数据库中不存在：{}",phone_number);
                err_rsp("用户手机号未注册");
                return;
            }

            // 5. 将新的手机号更新到数据库中
            ret->phone_number(phone_number);

              if(_mysql_user->Update(*ret) == false)
            {
                LOG_ERROR("用户签名插入数据库失败" );
                err_rsp("用户签名插入数据库失败");
                return;
            }
            // 6. 更新 ES 服务器中用户信息
            if(_es_user->Insert(*ret)== false)
            {
                LOG_ERROR("用户签名插入搜索引擎失败" );
                err_rsp("用户签名插入搜索引擎失败");
                return;
            }
            // 7. 组织响应，返回更新成功与否
            response->set_success(true);

        }
    private:
        //ServiceChannel::ChannelPtr  _channel;           //服务发现信道
        std::string _file_service_name;
        ServiceManage::ptr _service_manage;
        ESUser::ptr _es_user;                           //es搜索引擎
        ManageUser::ptr _mysql_user;                    //mysql对用户数据的管理
        Session::ptr _session;                          //会话管理
        Status::ptr  _status;                           //状态管理
        Codes::ptr   _codes;                            //验证码管理
    };

    class UserServer
    {
    public:
        using ptr = std::shared_ptr<UserServer>;
        UserServer(
            ServiceManage::ptr service_manage,
            Discovery::ptr discovery,
            Registration::ptr registration,
            std::shared_ptr<brpc::Server> server,
            std::shared_ptr<elasticlient::Client> es_client,
            std::shared_ptr<odb::mysql::database> mysql_client,
            std::shared_ptr<sw::redis::Redis> redis_client)
            :_discovery(discovery),
            _service_manage(service_manage),
            _registration(registration),
            _server(server),
            _es_client(es_client),
            _mysql_client(mysql_client),
            _redis_client(redis_client)
        {}
        ~UserServer(){}
        void Start()
        {
            _server->RunUntilAskedToQuit();
        }
    private:
        ServiceManage::ptr _service_manage;                 //服务发现信道管理
        Discovery::ptr _discovery;                          //服务发现
        Registration::ptr _registration;                    //etcd注册
        std::shared_ptr<brpc::Server> _server;              //rpc注册调用
        std::shared_ptr<elasticlient::Client> _es_client;   //es搜索引擎客户端
        std::shared_ptr<odb::mysql::database> _mysql_client;//mysql客户端
        std::shared_ptr<sw::redis::Redis> _redis_client;    //redis客户端
    };

    class UserServerBuilder
    {
    public:
        UserServerBuilder(){}
        ~UserServerBuilder(){}

        //构造服务发现信道
        void SetServiceManage(const std::string &service_name)
        {
            //1.创建对象
            _service_manage = std::make_shared<xu::ServiceManage>();
            //2.添加发现服务
            _service_manage->AddFollow(service_name);
        }
        //构造etcd发现
        void SetDiscovery(const std::string &etcd_host,const std::string &base_service)
        {
            if(!_service_manage)
            {
                LOG_ERROR("ServiceManage未初始化");
                return ;
            }
            //1.绑定回调函数
            auto put_cb = std::bind(&xu::ServiceManage::onServiceOnline, _service_manage.get(), std::placeholders::_1, std::placeholders::_2);
            auto del_cb = std::bind(&xu::ServiceManage::onServiceOffline, _service_manage.get(), std::placeholders::_1, std::placeholders::_2);
            //2. 构造服务发现对象
           _discovery = std::make_shared<xu::Discovery>(etcd_host,base_service, put_cb, del_cb);
        }
        //构造etcd注册
        void SetRegistration(const std::string &host,const std::string &service_name,
            const std::string &access_host)
        {
            _registration = std::make_shared<Registration>(host);
            _registration->AddKV(service_name,access_host);
        }

        //构造Es客户端
        void SetEsClient(const std::vector<std::string> &host_list)
        {
            _es_client = ESClientFactory::Create(host_list);
        }

        //构造Mysql客户端
        void SetMysqlClient(const std::string & user,
            const std::string &pswd,const std::string &db_name,
            const std::string &host,const std::string &cset)    
        {
            _mysql_client = MysqlClientFactory::Create(user,pswd,db_name,host,cset);
        }
        //构造Redis客户端
        void SetRedisClient(const std::string &ip ,int port,int db, bool keep_alive)
        {
            _redis_client = RedisClientFactory::Create(ip,port,db,keep_alive);
        }
        //构造rpc注册调用
        void SetRpcServer(uint16_t port, int32_t timeout, uint8_t num_threads, const std::string & service_name)
        {
            if(!_service_manage)
            {
                LOG_ERROR("ServiceManage未初始化");
                return ;
            }

            if(!_es_client)
            {
                LOG_ERROR("EsClient未初始化");
                return ;
            }

            if(!_mysql_client)
            {
                LOG_ERROR("MysqlClient未初始化");
                return ;
            }
            
            if(!_redis_client)
            {
                LOG_ERROR("RedisClient未初始化");
                return ;
            }

            _server = std::make_shared<brpc::Server>();

            UserServicelmpl *user_service = new  UserServicelmpl(service_name, _service_manage,
            _es_client, _mysql_client,_redis_client);
            _server->AddService(user_service,brpc::ServiceOwnership::SERVER_OWNS_SERVICE);

            brpc::ServerOptions options;
            options.idle_timeout_sec = timeout;
            options.num_threads = num_threads;

            _server->Start(port, &options);
        }

        //构造UserServer
        UserServer::ptr Build()
        {
            if(!_registration)
            {
                LOG_ERROR("Registration未初始化");
                return UserServer::ptr();
            }

             if(!_discovery)
            {
                LOG_ERROR("Discovery未初始化");
                return UserServer::ptr();
            }

            if(!_server)
            {
                LOG_ERROR("RpcServer未初始化");
                return UserServer::ptr();
            }

            auto res = std::make_shared<UserServer>(_service_manage,_discovery,_registration,
            _server,_es_client,_mysql_client,_redis_client);
            return res;
        }

    private:
        ServiceManage::ptr _service_manage;                 //服务发现信道管理
        Discovery::ptr _discovery;                          //服务发现
        Registration::ptr _registration;                    //etcd注册
        std::shared_ptr<elasticlient::Client> _es_client;   //es搜索引擎客户端
        std::shared_ptr<odb::mysql::database> _mysql_client;//mysql客户端
        std::shared_ptr<sw::redis::Redis> _redis_client;    //redis客户端
        std::shared_ptr<brpc::Server> _server;              //rpc注册调用     
    };
}
